/// \file sroiq_language.cpp.
///============================================================================\n
/// Name        : sroiq_language.cpp\n
/// Author      : Gergely Lukacsy (info@dlog-reasoner.org)\n
/// Version     : 0.01\n
/// Copyright   : DERI\n
/// Description : Classes for representing SROIQ concept/role constructors,\n
///               and axioms, implementation file.\n
/// 
/// This file is part of the DParser and DLog 2 projects.\n
///============================================================================

#ifdef WIN32

/// Hash function used in case of win32 systems.
class NAMEDHASHER : public stdext::hash_compare <NAMED*> {
public:

	size_t operator() (NAMED* pNamed) const {
		return ATOMICHASH::hash(pNamed->getURI());
	}

	bool operator() (const NAMED* a1, const NAMED* a2) const {
		ASSERT(false);
	}
};

//@{
/// We use Google great hash_map implementation for storing symbol tables (win32 version).
typedef google::sparse_hash_set<ATOMICCONCEPT*, NAMEDHASHER, ATOMICCOMPARE > CONCEPTTABLE;
typedef google::sparse_hash_set<ATOMICROLE*, NAMEDHASHER, ATOMICCOMPARE > ROLETABLE;
typedef google::sparse_hash_set<INSTANCE*, NAMEDHASHER, ATOMICCOMPARE > INSTANCETABLE;
//@}

#endif // WIN32

#ifndef WIN32
/// We specialise the __gnu_cxx::hash template to the ATOMICCONCEPT* type.
namespace __gnu_cxx {
	/// We specialise the __gnu_cxx::hash template to the NAMED* type
	template<>
	struct hash<NAMED*> {
		size_t operator()(NAMED* pNamed) const {
			return ATOMICHASH::hash(pNamed->getURI());
		}
	};

}

//@{
/// We use Google great hash_map implementation for storing symbol tables (mac OS version).
typedef google::sparse_hash_set<ATOMICCONCEPT*, __gnu_cxx::hash<NAMED*>, ATOMICCOMPARE > CONCEPTTABLE;
typedef google::sparse_hash_set<ATOMICROLE*, __gnu_cxx::hash<NAMED*>, ATOMICCOMPARE > ROLETABLE;
typedef google::sparse_hash_set<INSTANCE*, __gnu_cxx::hash<NAMED*>, ATOMICCOMPARE > INSTANCETABLE;
//@}
#endif

//@{
/// Typedefs for atomtables that are platform independent.
typedef std::pair<CONCEPTTABLE::iterator, bool> CONCEPTTABLENSERTRESULT;
typedef CONCEPTTABLE::const_iterator CONCEPTTABLECONSTITERATOR;
typedef CONCEPTTABLE::iterator CONCEPTTABLEITERATOR;

typedef std::pair<ROLETABLE::iterator, bool> ROLETABLENSERTRESULT;
typedef ROLETABLE::const_iterator ROLETABLECONSTITERATOR;
typedef ROLETABLE::iterator ROLETABLEITERATOR;

typedef std::pair<INSTANCETABLE::iterator, bool> INSTANCETABLENSERTRESULT;
typedef INSTANCETABLE::const_iterator INSTANCETABLECONSTITERATOR;
typedef INSTANCETABLE::iterator INSTANCETABLEITERATOR;
//@}


struct I_CONCEPTTABLE {
	CONCEPTTABLE mConceptTable;
};

struct I_ROLETABLE {
	ROLETABLE mRoleTable;
};

struct I_INSTANCETABLE {
	INSTANCETABLE mInstanceTable;
};

SROIQTERM::~SROIQTERM() {}

/// Default empty implementation.
void SROIQTERM::construct(CONCEPT* a) {
	ASSERT(false);
}

/// Default empty implementation.
void SROIQTERM::construct(ROLE* a) {
	ASSERT(false);
}

/// Default empty implementation.
void SROIQTERM::construct(INSTANCE* a) {
	ASSERT(false);
}

/// Default implementation.
bool SROIQTERM::isAssertion() {
	return false;
}

/// Default implementation.
bool ASSERTION::isAssertion() {
	return true;
}


/// Default implementation.
bool SROIQTERM::isLiteral() {
	return false;
}

/// Default implementation.
bool SROIQTERM::isInstance() {
	return false;
}

/// Default implementation.
bool INSTANCE::isInstance() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isFacet() {
	return false;
}

/// Default implementation.
bool SROIQTERM::isConcrete() {
	return false;
}

/// Default implementation.
bool SROIQTERM::isAtomic() {
	return false;
}

/// Default implementation.
bool SROIQTERM::isAxiom() {
	return false;
}

/// Default implementation.
bool AXIOM::isAxiom() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isConceptAxiom() {
	return false;
}

/// Default implementation.
bool CONCEPTAXIOM::isConceptAxiom() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isRoleAxiom() {
	return false;
}

/// Default implementation.
bool ROLEAXIOM::isRoleAxiom() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isExpression() {
	return false;
}

/// Default implementation.
bool EXPRESSION::isExpression() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isConcept() {
	return false;
}

/// Default implementation.
bool CONCEPT::isConcept() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isRole() {
	return false;
}

/// Default implementation.
bool ROLE::isRole() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isUnion() {
	return false;
}

/// Union implementation.
bool UNION::isUnion() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isIntersection() {
	return false;
}

/// Intersection implementation.
bool INTERSECTION::isIntersection() {
	return false;
}

/// Default implementation.
bool SROIQTERM::isExistential() {
	return false;
}

/// Exists implementation.
bool EXISTS::isExistential() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isUniversal() {
	return false;
}

/// Forall implementation.
bool FORALL::isUniversal() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isNegated() {
	return false;
}

/// Negated implementation.
bool NEGATED::isNegated() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isCardinality() {
	return false;
}

/// Default implementation.
bool CARDINALITY::isCardinality() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isHasSelf() {
	return false;
}

/// Default implementation.
bool HASSELF::isHasSelf() {
	return true;
}

/// Default implementation.
bool SROIQTERM::isNominal() {
	return false;
}

/// Default implementation.
bool NOMINAL::isNominal() {
	return true;
}


/// Default implementation.
bool SROIQTERM::isRestriction() {
	return false;
}

/// Default implementation.
bool RESTRICTION::isRestriction() {
	return true;
}

// ************************
// NAMED
// ************************

NAMED::NAMED()
	:mProperties(0) {}

/// Blindly copy the URI, but keeping the internal state.
void NAMED::setURIUnsafe(const char* pPrefix, const char* pName) {
	// set pointers
	mURI.pPrefix = pPrefix;
	mURI.pLocalName = pName;
}

ATOMICIDENTIFIER NAMED::getURI() {
	return mURI;
}


void NAMED::extendProperty(DWORD flag) {
	mProperties |= flag;
}

bool NAMED::hasProperty(DWORD flag) {
	return ((mProperties & flag) != 0);
}

DWORD NAMED::getProperties() {
	return mProperties;
}

// ************************
// cinstance
// ************************

CINSTANCE::CINSTANCE(PARAMETERS& params):
	pConcept(NULL),
	pInstance(NULL) {}

void CINSTANCE::construct(INSTANCE* pInstanceToAdd) {
	ASSERT(pInstance == NULL);
	pInstance = pInstanceToAdd;
}

void CINSTANCE::construct(CONCEPT* pConceptToAdd) {
	ASSERT(pConcept == NULL);
	pConcept = pConceptToAdd;
}

void CINSTANCE::insert(SROIQKB* pKB) {
	pKB->mABox.mConceptAssertions.push_back(this);
}

// ************************
// rinstance
// ************************

RINSTANCE::RINSTANCE(PARAMETERS& params):
	pRole(NULL),
	pInstanceSource(NULL),
	pInstanceTarget(NULL),
	mType(valPOSITIVE) {
	PARAMETERSITERATOR iter = params.find(parASSERTIONTYPE);
	if (iter != params.end()) {
		mType = static_cast<ASSTYPES>(iter->second.nValue);
	}
}

void RINSTANCE::construct(INSTANCE* pInstance) {
	if (pInstanceSource == NULL) {
		pInstanceSource = pInstance;
	} else {
		ASSERT(pInstanceTarget == NULL);
		pInstanceTarget = pInstance;
	}

}

void RINSTANCE::construct(ROLE* pRoleToAdd) {
	ASSERT(pRole == NULL);
	pRole = pRoleToAdd;
}

void RINSTANCE::insert(SROIQKB* pKB) {
	pKB->mABox.mRoleAssertions.push_back(this);
}

// ************************
// same instance
// ************************

SAMEINSTANCES::SAMEINSTANCES(PARAMETERS& params) {}

void SAMEINSTANCES::construct(INSTANCE* pInstanceToAdd) {
	mInstances.push_back(pInstanceToAdd);
}

void SAMEINSTANCES::insert(SROIQKB* pKB) {
	pKB->mABox.mSameInstances.push_back(this);
}



// ************************
// different instances
// ************************

DIFFERENTINSTANCES::DIFFERENTINSTANCES(PARAMETERS& params) {}

void DIFFERENTINSTANCES::construct(INSTANCE* pInstanceToAdd) {
	mInstances.push_back(pInstanceToAdd);
}

void DIFFERENTINSTANCES::insert(SROIQKB* pKB) {
	pKB->mABox.mDifferentInstances.push_back(this);
}

// ************************
// HASKEY
// ************************

HASKEY::HASKEY(PARAMETERS& params):
	pConcept(NULL) {}

void HASKEY::construct(CONCEPT* pConceptToAdd) {
	ASSERT(pConcept == NULL);
	pConcept = pConceptToAdd;
}

void HASKEY::construct(ROLE* pRoleToAdd) {
	if (pRoleToAdd->isConcrete()) {
		ASSERT(pRoleToAdd->isAtomic());
		mDataTypeProperties.push_back(pRoleToAdd);
	} else {
		mObjectProperties.push_back(pRoleToAdd);
	}
}

void HASKEY::insert(SROIQKB* pKB) {
	pKB->mTBox.mKeys.push_back(this);
}


// ************************
// axiom "equivalent class"
// ************************

EQUIVALENTCONCEPTS::EQUIVALENTCONCEPTS(PARAMETERS& params):
	mOrigin(valNORMALEQ) {
	PARAMETERSITERATOR iter = params.find(parEQUIVALENTCONCEPTORIGIN);
	if (iter != params.end()) {
		mOrigin = static_cast<EQTYPES>(iter->second.nValue);
	}
}

// add a finalised concept to the list of equivalences
void EQUIVALENTCONCEPTS::construct(CONCEPT* pConcept) {
	// check if we an in a special mode needed for disjointUnionOf
	if (mOrigin == valDISJOINTUNION) {

		// check if this is the first concept
		if (mConcepts.empty()) {
			// push concept
			mConcepts.push_back(pConcept);

			// create a non-instantiated UNION and push it to the second position
			PARAMETERS dummy;
			UNION* pNewUnion = new (SINGLETON::pKB->mPool) UNION(dummy);
			mConcepts.push_back(pNewUnion);

			// return
			return;
		}

		// pConcept belongs to the union
		UNION* pUnion = static_cast<UNION*>(mConcepts.back());
		pUnion->construct(pConcept);
	}

	// normal case
	mConcepts.push_back(pConcept);
}

void EQUIVALENTCONCEPTS::insert(SROIQKB* pKB) {
	pKB->mTBox.mEquivalenceAxioms.push_back(this);

	// if this is actually a disjoint union then we need to create also the appropriate
	// disjointconcepts axiom
	if (mOrigin == valDISJOINTUNION) {
		// create axiom
		PARAMETERS dummy;
		DISJOINTCONCEPTS* pNewDisjoints = new (pKB->mPool) DISJOINTCONCEPTS(dummy);

		// fill it
		pNewDisjoints->mConcepts = mConcepts;

		// insert it
		pKB->mTBox.mDisjointAxioms.push_back(pNewDisjoints);
	}

}


// ************************
// axiom "disjoint class"
// ************************

// add a finalised concept to the list of disjoints
void DISJOINTCONCEPTS::construct(CONCEPT* pConcept) {
	mConcepts.push_back(pConcept);
}

void DISJOINTCONCEPTS::insert(SROIQKB* pKB) {
	pKB->mTBox.mDisjointAxioms.push_back(this);
}


// ****************
// axiom "subclass"
// ****************

SUBCONCEPT::SUBCONCEPT(PARAMETERS& params):
	pLeftConcept(NULL),
	pRightConcept(NULL),
	mOrigin(valNORMALSUB) {

	PARAMETERSITERATOR iter = params.find(parSUBCONCEPTORIGIN);
	if (iter != params.end()) {
		mOrigin = static_cast<SUBTYPES>(iter->second.nValue);
	}
}

// Builds a domain/range expression.
// According to the OWL/XML grammar we assume that this is invoked before construct(CONCEPT*)
void SUBCONCEPT::construct(ROLE* pRole) {
	// We always create a forall expression.
	PARAMETERS dummy;
	FORALL* pNewForall = new (SINGLETON::pKB->mPool) FORALL(dummy);

	// If we are dealing with domain restriction we also need an inverse expression
	if (mOrigin == valDOMAIN) {
		INVERSE* pNewInverse = new (SINGLETON::pKB->mPool) INVERSE(dummy);

		// Add pRole to the inverse.
		pNewInverse->construct(pRole);

		// re-alias
		pRole = pNewInverse;
	}

	// Add role to the forall expression.
	pNewForall->construct(pRole);

	// insert this forall construct to the right hand side of the axiom
	pRightConcept = pNewForall;
}

// Adds a left- or right hand side concept.
void SUBCONCEPT::construct(CONCEPT* pConcept) {
	if ((mOrigin == valDOMAIN) || (mOrigin == valRANGE)) {
		ASSERT(pLeftConcept == NULL);
		ASSERT(pRightConcept != NULL);

		// set left concept to TOP
		pLeftConcept = SINGLETON::pKB->pTOP;

		// set the concept of the forall expression
		pRightConcept->construct(pConcept);

		// return
		return;
	}


	// In the normals case we continue normally.
	if (pLeftConcept == NULL) {
		ASSERT(pRightConcept == NULL);
		pLeftConcept = pConcept;
	} else {
		ASSERT(pRightConcept == NULL);
		pRightConcept = pConcept;
	}

}

void SUBCONCEPT::insert(SROIQKB* pKB) {
	pKB->mTBox.mSubsumptionAxioms.push_back(this);
}

// **********************
// axiom equivalent roles
// **********************

EQUIVALENTROLES::EQUIVALENTROLES(PARAMETERS& param):
	mOrigin(valNORMALER) {
	PARAMETERSITERATOR iter = param.find(parEQUIVALENTROLEORIGIN);
	if (iter != param.end()) {
		mOrigin = static_cast<ERTYPES>(iter->second.nValue);
	}
}

// add a finalised concept to the list of equivalences
void EQUIVALENTROLES::construct(ROLE* pRole) {
	// check if we an in a special mode
	if ((mOrigin == valINVERSES) && (mRoles.empty())) {
		// this means we will receive altogether two roles and one of the is the inverse of the other
		// now first role arrived, we create the inverse of it and insert it into mRoles
		PARAMETERS dummy;
		INVERSE* pNewInverse = new (SINGLETON::pKB->mPool) INVERSE(dummy);

		// construct inverse
		pNewInverse->construct(pRole);

		// re-alias to push
		pRole = pNewInverse;
	}

	// push role
	mRoles.push_back(pRole);
}

void EQUIVALENTROLES::insert(SROIQKB* pKB) {
	pKB->mRBox.mEquivalenceAxioms.push_back(this);
}

// **********************
// axiom disjoint roles
// **********************

// add a finalised concept to the list of disjoints
void DISJOINTROLES::construct(ROLE* pRole) {
	mRoles.push_back(pRole);
}

void DISJOINTROLES::insert(SROIQKB* pKB) {
	pKB->mRBox.mDisjointAxioms.push_back(this);
}

// ***************
// axiom "subrole"
// ***************

// add a left- or right hand side concept
// manages property chains as well
void SUBROLE::construct(ROLE* pRole) {

	// If this is the first role, let us definitely put it on the left hand side.
	if (mLeftRoles.empty()) {
		ASSERT(pRightRole == NULL);
		mLeftRoles.push_back(pRole);
		return;
	}

	// If this is the second role, let us put it on the right hand side.
	// In most cases this is the end of construction.
	if (pRightRole == NULL) {
		ASSERT(!mLeftRoles.empty());
		pRightRole = pRole;
		return;
	}

	// Now we are dealing with a property chain.
	// We simply relocate pRightRole into the left hand side and refresh right hand side with pRole
	ASSERT(!mLeftRoles.empty());
	ASSERT(pRightRole != NULL);
	mLeftRoles.push_back(pRightRole);
	pRightRole = pRole;
}

void SUBROLE::insert(SROIQKB* pKB) {
	pKB->mRBox.mSubsumptionAxioms.push_back(this);
}

// ***************************************
// atomic constructs
// ***************************************


// ***************
// atomic concepts
// ***************
ATOMICCONCEPT::ATOMICCONCEPT(PARAMETERS& params) {}

void ATOMICCONCEPT::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

bool ATOMICCONCEPT::isConcrete() {
	return hasProperty(bCONCRETE);
}

bool ATOMICCONCEPT::isAtomic() {
	return true;
}


// ************
// atomic roles
// ************
ATOMICROLE::ATOMICROLE(PARAMETERS& params) {}

void ATOMICROLE::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

bool ATOMICROLE::isAtomic() {
	return true;
}

bool ATOMICROLE::isConcrete() {
	return hasProperty(bCONCRETE);
}

// ************************
// instance
// ************************


INSTANCE::INSTANCE(PARAMETERS& params) {}

void INSTANCE::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

bool INSTANCE::isLiteral() {
	return (hasProperty(bLITERAL));
}

bool INSTANCE::isAtomic() {
	return true;
}

bool INSTANCE::isConcrete() {
	return isLiteral();
}

// ********
// negation
// ********
void NEGATED::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void NEGATED::construct(CONCEPT* pConceptToNegate) {
	ASSERT(pConcept == NULL);
	pConcept = pConceptToNegate;
}

// A negation is a DataComplementOf iff the internal concept is concrete.
bool NEGATED::isConcrete() {
	ASSERT(pConcept != NULL);
	return pConcept->isConcrete();
}

// ********
// inverse
// ********
INVERSE::INVERSE(PARAMETERS& params): pRole(NULL) {};

void INVERSE::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void INVERSE::construct(ROLE* pRoleToInvert) {
	ASSERT(pRole == NULL);
	pRole = pRoleToInvert;
}

// ********
// has self
// ********
HASSELF::HASSELF(PARAMETERS& params): pRole(NULL) {};

void HASSELF::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void HASSELF::construct(ROLE* pSelfRole) {
	ASSERT(pRole == NULL);
	pRole = pSelfRole;
}


// ****
// intersection
// ****
void INTERSECTION::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

// add a finalised concept to the internal list of concepts
void INTERSECTION::construct(CONCEPT* pConcept) {
	mConcepts.push_back(pConcept);
}

// An intersection is a DataIntersectionOf iff the concepts it contains are concrete.
bool INTERSECTION::isConcrete() {
	ASSERT(!mConcepts.empty());
	return mConcepts.front()->isConcrete();
}

// ****
// Nominal
// ****

NOMINAL::NOMINAL(PARAMETERS& param) {}

void NOMINAL::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void NOMINAL::construct(INSTANCE* pInstanceToAdd) {
	pInstance = pInstanceToAdd;
}

// A negation is a DataComplementOf iff the internal concept is concrete.
bool NOMINAL::isConcrete() {
	ASSERT(pInstance != NULL);
	return pInstance->isConcrete();
}

// ****
// Facet
// ****

FACET::FACET(PARAMETERS& params) {
	// We deal with the type parameter
	PARAMETERSITERATOR iter = params.find(parFACETDESCRIPTION);

	ASSERT(iter != params.end());

	char* pDescription = new (SINGLETON::pKB->mPool) char[strlen(iter->second.pString) + 1];
	strcpy(pDescription,iter->second.pString);
	pFacetDescription = pDescription;
}

void FACET::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void FACET::construct(INSTANCE* pLiteralToAdd) {
	ASSERT(pLiteralToAdd->isLiteral());
	pLiteral = pLiteralToAdd;
}

bool FACET::isFacet() {
	return true;
}

// ****
// Restriction
// ****

RESTRICTION::RESTRICTION(PARAMETERS& params):
	pDataType(NULL) {}

void RESTRICTION::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

void RESTRICTION::construct(CONCEPT* pConcept) {
	if (pDataType == NULL) {
		// register the datatype which we will restrict using facets
		ASSERT(pConcept->isAtomic());
		pDataType = static_cast<ATOMICCONCEPT*>(pConcept);

		// return
		return;
	}

	ASSERT(pConcept->isFacet());
	mFacets.push_back(pConcept);
}


// ****
// union
// ****
UNION::UNION(PARAMETERS& params) {}

void UNION::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	// create a double dispatch
	pGenericTerm->construct(this);
}

// add a finalised concept to the internal list of concepts
void UNION::construct(CONCEPT* pConcept) {
	mConcepts.push_back(pConcept);
}

// add a finalised instance to the list of concepts as nominal
void UNION::construct(INSTANCE* pInstance) {
	// create new nominal
	PARAMETERS dummy;
	NOMINAL* pNominal = new (SINGLETON::pKB->mPool) NOMINAL(dummy);

	// instantiate nominal
	pNominal->construct(pInstance);

	// insert nominal
	mConcepts.push_back(pNominal);
}

// A union is a DataUnionOf iff the concepts it contains are concrete.
bool UNION::isConcrete() {
	ASSERT(!mConcepts.empty());
	return mConcepts.front()->isConcrete();
}

// ************************
// existential restrictions
// ************************

/// Performs the necessary double-dispatch.
void EXISTS::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	/// performs a double dispatch
	pGenericTerm->construct(this);
}

/// Adds a finalised concept to the concept position.
void EXISTS::construct(CONCEPT* pFinalisedConcept) {
	ASSERT(pConcept == NULL);
	pConcept=pFinalisedConcept;
}

/// Adds a finalised instance as nominal to the concept position.
void EXISTS::construct(INSTANCE* pInstance) {
	ASSERT(pConcept == NULL);

	// create new nominal
	PARAMETERS dummy;
	NOMINAL* pNominal = new (SINGLETON::pKB->mPool) NOMINAL(dummy);

	// instantiate nominal
	pNominal->construct(pInstance);

	// register nominal
	pConcept=pNominal;
}

/// Adds a finalised role to the role position
void EXISTS::construct(ROLE* pFinalisedRole) {
	ASSERT(pRole == NULL);
	pRole=pFinalisedRole;
}

// **********************
// universal restrictions
// **********************

/// Performs the necessary double-dispatch.
void FORALL::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	/// performs a double dispatch
	pGenericTerm->construct(this);
}

/// Adds a finalised concept to the concept position
void FORALL::construct(CONCEPT* pFinalisedConcept) {
	ASSERT(pConcept == NULL);
	pConcept=pFinalisedConcept;
}

/// Adds a finalised role to the role position
void FORALL::construct(ROLE* pFinalisedRole) {
	ASSERT(pRole == NULL);
	pRole=pFinalisedRole;
}

// ***********************************
// cardinality restrictions (at-least)
// ***********************************

CARDINALITY::CARDINALITY(PARAMETERS& params):
	pRole(NULL),
	pConcept(NULL) {

	// First we deal with the cardinality parameter
	PARAMETERSITERATOR iter = params.find(parCARDINALITY);
	ASSERT(iter != params.end());

	unsigned nConvResult = 0;
	INT nResult = sscanf(iter->second.pString, "%d", &nConvResult);
	ASSERT(nResult != EOF);
	// it is safe to give this value into a 30 bit unsigned
	nCardinality = nConvResult;

	// Second, we deal with the type
	iter = params.find(parCARDINALITYTYPE);
	ASSERT(iter != params.end());
	ASSERT(iter->second.nValue == valMINCARDINALITY || iter->second.nValue == valMAXCARDINALITY || iter->second.nValue == valEXACTCARDINALITY);
	mType = iter->second.nValue;
}

/// Performs the necessary double-dispatch.
void CARDINALITY::dispatchConstructInvocation(SROIQTERM* pGenericTerm) {
	/// performs a double dispatch
	pGenericTerm->construct(this);
}

/// Adds a finalised concept to the concept position
void CARDINALITY::construct(CONCEPT* pFinalisedConcept) {
	ASSERT(pConcept == NULL);
	pConcept=pFinalisedConcept;
}

/// Adds a finalised role to the role position
void CARDINALITY::construct(ROLE* pFinalisedRole) {
	ASSERT(pRole == NULL);
	pRole=pFinalisedRole;
}


// ********************
// SROIQ knowledge base
// ********************
const INT SROIQKB::nrGrouppedObjects = 1000;

// constructor
SROIQKB::SROIQKB():
	mPool(sizeof(CARDINALITY) * nrGrouppedObjects) {
	DBG("SROIQ KB constructor");

	// create atom tables
	pConceptTable = new I_CONCEPTTABLE();
	pRoleTable = new I_ROLETABLE();
	pInstanceTable = new I_INSTANCETABLE();

	// create top and bottom
	PARAMETERS v;
	char* pOWL = "http://www.w3.org/2002/07/owl#";
	pTOP = new (mPool) ATOMICCONCEPT(v);
	pTOP->setURIUnsafe(pOWL, "Thing");
	addAtomic(pTOP);

	pBOTTOM = new (mPool) ATOMICCONCEPT(v);
	pBOTTOM->setURIUnsafe(pOWL, "Nothing");
	addAtomic(pBOTTOM);
}

// destructor
SROIQKB::~SROIQKB() {
	delete pConceptTable;
	delete pRoleTable;
	delete pInstanceTable;
}

template <typename A, typename T>
A* SROIQKB::_addAtomic(A* pElementToAdd, T& mTable) {
	// checkup
	ASSERT(pElementToAdd != NULL);

	// try inserting pConceptToAdd to the table
	std::pair<typename T::iterator, bool> result = mTable.insert(pElementToAdd);

	// chekups
	ASSERT((result.second == false) || (*(result.first) == pElementToAdd));
	ASSERT((result.second == true) || (*(result.first) != pElementToAdd));

#ifdef DEBUG
	if (result.second == true) {
		DBG("\t\tAtomic element \"%s%s\" has been inserted to the cache.",pElementToAdd->getURI().pPrefix, pElementToAdd->getURI().pLocalName);
	}
#endif

	// regardless of whether this has been already on the table we can return
	return *(result.first);
}

ATOMICCONCEPT* SROIQKB::addAtomic(ATOMICCONCEPT* pConceptToAdd) {
	// delegate insert
	ATOMICCONCEPT* pNewConcept = _addAtomic<ATOMICCONCEPT, CONCEPTTABLE>(pConceptToAdd, pConceptTable->mConceptTable);

	if (pNewConcept != pConceptToAdd) {
		// Properties of an atomic concept simply cannot change.
		ASSERT(pNewConcept->getProperties() == pConceptToAdd->getProperties());
		DBG("\t\tAtomic concept \"%s%s\" has been found in cache.",pConceptToAdd->getURI().pPrefix, pConceptToAdd->getURI().pLocalName);
	}

	return pNewConcept;
}

ATOMICROLE* SROIQKB::addAtomic(ATOMICROLE* pRoleToAdd) {
	// delegate insert
	ATOMICROLE* pNewRole = _addAtomic<ATOMICROLE, ROLETABLE>(pRoleToAdd, pRoleTable->mRoleTable);

	// if role was already in the table, refresh its attributes field and cleanup
	if (pNewRole != pRoleToAdd) {
		pNewRole->extendProperty(pRoleToAdd->getProperties());
		DBG("\t\tAtomic role \"%s%s\" has been found in cache and now its properties are updated with %d.",pRoleToAdd->getURI().pPrefix, pRoleToAdd->getURI().pLocalName, pRoleToAdd->getProperties());
	}

	// return
	return pNewRole;
}

INSTANCE* SROIQKB::addAtomic(INSTANCE* pInstanceToAdd) {
	// delegate insert
	INSTANCE* pNewInstance = _addAtomic<INSTANCE, INSTANCETABLE>(pInstanceToAdd, pInstanceTable->mInstanceTable);

	if (pNewInstance != pInstanceToAdd) {
		// Properties of an instance simply cannot change.
		ASSERT(pNewInstance->getProperties() == pInstanceToAdd->getProperties());
		DBG("\t\tInstance \"%s%s\" has been found in cache.",pInstanceToAdd->getURI().pPrefix, pInstanceToAdd->getURI().pLocalName);
	}

	return pNewInstance;
}
